package nr.co.mhgames.polyanim.renderer;

import nr.co.mhgames.polyanim.Animation;
import nr.co.mhgames.polyanim.Group;
import nr.co.mhgames.polyanim.KeyFrame;
import nr.co.mhgames.polyanim.Polygon;
import nr.co.mhgames.polyanim.renderer.modifiers.ColorModifier;
import nr.co.mhgames.polyanim.renderer.modifiers.HSLModifier;
import nr.co.mhgames.polyanim.renderer.modifiers.RenderModifier;
import nr.co.mhgames.polyanim.util.ColorDef;

/**
 * Base PolyAnim renderer. It's the base class for every other PolyAnim
 * renderer.
 * 
 * @author Mika Halttunen
 */
public abstract class AnimRenderer {
	/** Renderer singleton instance */
	private static AnimRenderer singleton;

	/** Available renderer types */
	public static enum RendererType {
		NONE, JAVA2D, LWJGL,
	}

	/** Renderer type */
	private static RendererType type = RendererType.NONE;

	/** Should the renderer draw outlines on the polygons? */
	protected boolean drawOutlines = false;

	/** Temporary color def */
	protected final ColorDef tmpColor = new ColorDef();

	/** Active render modifiers */
	protected static class ActiveModifiers {
		/** Currently active HSL modifier (can be <code>null</code>) */
		protected static HSLModifier activeHSL;

		/** Previously active HSL modifier */
		protected static HSLModifier previouslyActiveHSL;

		/** Currently active coloring modifier (can be <code>null</code>) */
		protected static ColorModifier activeColoring;

		/** Previously active coloring modifier */
		protected static ColorModifier previouslyActiveColoring;

		/** Current alpha modifier factor */
		protected static float alphaFactor = 1.0f;
	}


	/**
	 * Returns the renderer singleton instance. Before using this,
	 * {@link AnimRenderer#setType(RendererType)} must be called to select the
	 * desired renderer.
	 * 
	 * @return AnimRenderer instance
	 */
	public static AnimRenderer getInstance() {
		if (type == RendererType.NONE)
			return null;
		if (singleton == null) {
			switch (type) {
			default:
			case JAVA2D:
				singleton = Java2DAnimRenderer.getInstance();
				break;
			case LWJGL:
				singleton = LWJGLAnimRenderer.getInstance();
				break;
			}
		}

		return singleton;
	}

	/** Return the renderer type */
	public static RendererType getType() {
		return type;
	}

	/**
	 * Set the renderer type. This must be called before {@link #getInstance()}
	 * is used.
	 */
	public static void setType(RendererType rtype) {
		type = rtype;
	}

	/**
	 * Return the renderer identifier. Derived renderers must implement this.
	 * 
	 * @return Identifier string
	 */
	public abstract String getIdentifier();


	/**
	 * Render the given polygon. Derived renderers must implement this.
	 * 
	 * @param poly
	 *            Polygon to render
	 */
	public abstract void renderPolygon(Polygon poly);

	/**
	 * Render the given polygon group. Derived renderers must implement this.
	 * 
	 * @param group
	 *            Polygon group to render
	 */
	public abstract void renderGroup(Group group);

	/**
	 * Render the given key frame. Derived renderers must implement this.
	 * 
	 * @param frame
	 *            Frame to render
	 */
	public abstract void renderKeyFrame(KeyFrame frame);

	/**
	 * Render the given animation. Derived renderers must implement this.
	 * 
	 * @param anim
	 *            Animation to render
	 */
	public abstract void renderAnimation(Animation anim);

	/**
	 * Render the given animation with the specified offset. Derived renderers
	 * must implement this.
	 * 
	 * @param anim
	 *            Animation to render
	 * @param offsetX
	 *            Offset in X direction
	 * @param offsetY
	 *            Offset in Y direction
	 */
	public abstract void renderAnimation(Animation anim, float offsetX, float offsetY);

	/**
	 * Render the given animaion with the specified offset and render modifiers
	 * (such as flip). Derived renderers should override this, if they want to
	 * support the modifiers.
	 * 
	 * @param anim
	 *            Animation to render
	 * @param offsetX
	 *            Offset in X direction
	 * @param offsetY
	 *            Offset in Y direction
	 * @param modifiers
	 *            Array of render modifiers
	 */
	public void renderAnimation(Animation anim, float offsetX, float offsetY,
			RenderModifier... modifiers) {
	}

	/**
	 * Set whether to render the polygon outlines, or not.
	 * 
	 * @param outlines
	 *            If true, render the outlines
	 */
	public void setDrawOutlines(boolean outlines) {
		drawOutlines = outlines;
	}

	/**
	 * Return whether to render the polygon outlines, or not.
	 * 
	 * @return If true, render the outlines
	 */
	public boolean shouldDrawOutlines() {
		return drawOutlines;
	}


	/** Stores the HSL and color modifiers */
	protected void storeRenderModifiers() {
		ActiveModifiers.previouslyActiveHSL = ActiveModifiers.activeHSL;
		ActiveModifiers.previouslyActiveColoring = ActiveModifiers.activeColoring;
	}

	/** Restores the HSL and color modifiers */
	protected void restoreRenderModifiers() {
		ActiveModifiers.activeHSL = ActiveModifiers.previouslyActiveHSL;
		ActiveModifiers.activeColoring = ActiveModifiers.previouslyActiveColoring;
		ActiveModifiers.alphaFactor = 1.0f;
	}
}
